package calao.storage;

import java.util.BitSet;
import java.util.Vector;

/** A record search based on a set of conditions.
 * 
 * @author <a href="mailto:nifa@signal25.com">Nicolas Faivre</a>
 */ 
public class Search {
	
	final Table table;
	final Vector<FieldCondition> condList = new Vector<FieldCondition>();
	BitSet searchedFields;
	boolean distinctOn = false;
	Field[] sortFields;
	
	/** Creates a new search.
	 * 
	 * @param table the table to search for records.
	 */
	public Search(Table table)
	{
		this.table = table;
		this.searchedFields = new BitSet(table.getFieldCount());
		searchedFields.set(0, table.getFieldCount(), true);
	}
	
	/** Adds a new condition to this search.
	 */
	public void add(FieldCondition cond)
	{
		condList.add(cond);
	}
	
	/** Limits this search to a set of fields.
	 * 
	 * @param fields
	 */
	public void limitTo(Field... fields)
	{
		searchedFields.set(0, table.getFieldCount(), false);
		for (Field field : fields) searchedFields.set(field.getPosition(), true);
	}
	
	/** Gets the searched table.
	 */
	public Table getTable()
	{
		return table;
	}
	
	/** Gets the field conditions in this search.
	 */
	public Iterable<FieldCondition> getConditions()
	{
		return condList;
	}
	
	/** Checks whether a field is part of this search.
	 * Fields that are not considered part of this search will not be fetched.
	 */
	public boolean isSearched(Field field)
	{
		return searchedFields.get(field.getPosition());
	}

	/** Gets the first equal condition on a field.
	 */
	public EqualCondition getFirstEqualCondition(Field field)
	{
		for (int n=0; n<condList.size(); n++) {
			FieldCondition nthCond = condList.get(n);
			if (nthCond.field==field && nthCond.getClass()==EqualCondition.class) {
				return (EqualCondition)nthCond;
			}
		}
		return null;
	}
		
	/** Gets the first range condition on a field.
	 */
	public RangeCondition getFirstRangeCondition(Field field)
	{
		for (int n=0; n<condList.size(); n++) {
			FieldCondition nthCond = condList.get(n);
			if (nthCond.field==field && nthCond.getClass()==RangeCondition.class) {
				return (RangeCondition)nthCond;
			}
		}
		return null;
	}

	/** Gets the first start condition on a field.
	 */
	public StartCondition getFirstStartCondition(Field field)
	{
		for (int n=0; n<condList.size(); n++) {
			FieldCondition nthCond = condList.get(n);
			if (nthCond.field==field && nthCond.getClass()==StartCondition.class) {
				return (StartCondition)nthCond;
			}
		}
		return null;
	}
	
	/** Sets whether this search shall return distinct records only.
	 */
	public void setDistinct(boolean trueOrFalse)
	{
		distinctOn = trueOrFalse;
	}

	/** Checks whether this search shall return distinct records only.
	 */
	public boolean getDistinct()
	{
		return distinctOn;
	}
	
	/** Sorts results according to one or more fields.
	 */
	public void sortBy(Field... fields)
	{
		sortFields = fields;
	}

	/** Gets fields used to sort results.
	 */
	public Field[] getSortFields()
	{
		return sortFields;
	}

}
